# -*- coding: utf-8 -*-
'''
Created on 09/nov/2009

@author: sax
'''

from django import forms, template

#from django.contrib.admin import helpers, widgets
#from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_ngettext, model_format_dict
#from django.contrib.contenttypes.models import ContentType
#from django.core.exceptions import PermissionDenied
from django.db import models, transaction
#from django.db.models.fields import BLANK_CHOICE_DASH
#from django.forms.formsets import all_valid
#from django.forms.models import BaseInlineFormSet, modelform_factory, modelformset_factory, inlineformset_factory
#from django.http import Http404, HttpResponse, HttpResponseRedirect
#from django.shortcuts import get_object_or_404, render_to_response
#from django.utils.datastructures import SortedDict
#from django.utils.encoding import force_unicode
#from django.utils.functional import curry, update_wrapper
#from django.utils.html import escape
#from django.utils.safestring import mark_safe
#from django.utils.text import capfirst, get_text_list
#from django.utils.translation import ugettext as _, ungettext, ugettext_lazy
from xadmin import widgets
from xadmin import ajax
#try:


HORIZONTAL, VERTICAL = 1, 2
# returns the <ul> class for a given radio_admin field
get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')


FORMFIELD_FOR_DBFIELD_DEFAULTS = {
    models.DateTimeField: {
        'form_class': forms.SplitDateTimeField,
        'widget': widgets.AdminSplitDateTime
    },
    models.DateField:   {'widget': ajax.DatePickerWidget},
    models.URLField:    {'widget': widgets.URLWidget},
    #models.DateField:    {'widget': widgets.AdminDateWidget},
    models.TimeField:    {'widget': widgets.AdminTimeWidget},
    models.TextField:    {'widget': widgets.AdminTextareaWidget},
    #models.URLField:     {'widget': widgets.AdminURLFieldWidget},
    models.IntegerField: {'widget': widgets.AdminIntegerFieldWidget},
    models.CharField:    {'widget': widgets.AdminTextInputWidget},
    models.ImageField:   {'widget': widgets.AdminFileWidget},
    models.FileField:    {'widget': widgets.AdminFileWidget},
}

from xadmin.options.strategies import *

     
        
class BaseModelAdmin( object ):
    """Functionality common to both ModelAdmin and InlineAdmin."""
    __metaclass__ = forms.MediaDefiningClass

    raw_id_fields = ()
    fields = None
    exclude = None
    fieldsets = None
    form = forms.ModelForm
    filter_vertical = ()
    filter_horizontal = ()
    radio_fields = {}
    prepopulated_fields = {}
    formfield_overrides = {}
    read_only_fields = ()
    _strategies = []
    
    fk_service_viewname = None

    _MODE_CHANGE = 1
    _MODE_ADD = 2
    _MODE_LIST = 3
    _MODE_DELETE = 3
    _MODE_UNKNOW = 4
    
    def __init__(self):        
        self.formfield_overrides = dict(FORMFIELD_FOR_DBFIELD_DEFAULTS, **self.formfield_overrides)
        self.__mode = BaseModelAdmin._MODE_UNKNOW
        for x in self._strategies:
            setattr(self, x, True)
            
    def set_mode(self, mode):
        if not mode in (BaseModelAdmin._MODE_CHANGE, BaseModelAdmin._MODE_ADD, 
                        BaseModelAdmin._MODE_LIST, BaseModelAdmin._MODE_DELETE):
            raise Exception("Invalid mode for XmodelAdmin")
        self.__mode = mode
    
    def get_mode(self):
        return self.__mode
    
    mode = property(get_mode, set_mode)
    
    def is_adding(self):
        return self.__mode == BaseModelAdmin._MODE_ADD
    
    def is_editing(self):
        return self.__mode == BaseModelAdmin._MODE_CHANGE

    def is_listing(self):
        return self.__mode == BaseModelAdmin._MODE_LIST

    def is_read_only_field(self, db_field_name):
        return (db_field_name in self.read_only_fields) and \
                    (self.__mode in ( BaseModelAdmin._MODE_CHANGE, BaseModelAdmin._MODE_LIST))
            
    
    def formfield_for_dbfield(self, db_field, **kwargs):
        """
        Hook for specifying the form Field instance for a given database Field
        instance.

        If kwargs are given, they're passed to the form Field's constructor.
        """
        request = kwargs.pop("request", None)

        # If the field specifies choices, we don't need to look for special
        # admin widgets - we just need to use a select widget of some kind.
        if db_field.choices:
            return self.formfield_for_choice_field(db_field, request, **kwargs)

        # ForeignKey or ManyToManyFields
        if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)):
            # Combine the field kwargs with any options for formfield_overrides.
            # Make sure the passed in **kwargs override anything in
            # formfield_overrides because **kwargs is more specific, and should
            # always win.
            if db_field.__class__ in self.formfield_overrides:
                kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs)

            # Get the correct formfield.
            if isinstance(db_field, models.ForeignKey):
                formfield = self.formfield_for_foreignkey(db_field, request, **kwargs)
            elif isinstance(db_field, models.ManyToManyField):
                formfield = self.formfield_for_manytomany(db_field, request, **kwargs)

            # For non-raw_id fields, wrap the widget with a wrapper that adds
            # extra HTML -- the "add other" interface -- to the end of the
            # rendered output. formfield can be None if it came from a
            # OneToOneField with parent_link=True or a M2M intermediary.
            if formfield and db_field.name not in self.raw_id_fields:
                formfield.widget = widgets.RelatedFieldWidgetWrapper(formfield.widget, db_field.rel, self.admin_site)
            
            if self.is_read_only_field(db_field.name):
                formfield.widget.__class__ = widgets.ForeignKeyReadOnlyWidget
                
            return formfield

        # =X= read only fields handling 
        if self.is_read_only_field(db_field.name):
            kwargs['widget'] = widgets.LabelWidget
        else:
            # If we've got overrides for the formfield defined, use 'em. **kwargs
            # passed to formfield_for_dbfield override the defaults.
            for klass in db_field.__class__.mro():
                if klass in self.formfield_overrides:
                    kwargs = dict(self.formfield_overrides[klass], **kwargs)
                    return db_field.formfield(**kwargs)

        # For any other type of field, just call its formfield() method.
        return db_field.formfield(**kwargs)

    def formfield_for_choice_field(self, db_field, request=None, **kwargs):
        """
        Get a form Field for a database Field that has declared choices.
        """
        # If the field is named as a radio_field, use a RadioSelect
        if db_field.name in self.radio_fields:
            # Avoid stomping on custom widget/choices arguments.
            if 'widget' not in kwargs:
                kwargs['widget'] = widgets.AdminRadioSelect(attrs={
                    'class': get_ul_class(self.radio_fields[db_field.name]),
                })
            if 'choices' not in kwargs:
                kwargs['choices'] = db_field.get_choices(
                    include_blank = db_field.blank,
                    blank_choice=[('', _('None'))]
                )
        return db_field.formfield(**kwargs)

    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
        """
        Get a form Field for a ForeignKey.
        """
        fk_model_admin = self.admin_site._registry.get(db_field.rel.to)
        if fk_model_admin and getattr(fk_model_admin, 'fk_service', None):
                view_name = "%s:%s" % (self.admin_site.name, fk_model_admin.fk_service_viewname)
                kwargs['widget'] = ajax.AjaxLookupInput(view_name)
                
        elif db_field.name in self.raw_id_fields:
            kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel)
        elif db_field.name in self.radio_fields:
            kwargs['widget'] = widgets.AdminRadioSelect(attrs={
                'class': get_ul_class(self.radio_fields[db_field.name]),
            })
            kwargs['empty_label'] = db_field.blank and _('None') or None
            
        
        return db_field.formfield(**kwargs)

    def formfield_for_manytomany(self, db_field, request=None, **kwargs):
        """
        Get a form Field for a ManyToManyField.
        """
        # If it uses an intermediary model, don't show field in admin.
        if db_field.rel.through is not None:
            return None

        if db_field.name in self.raw_id_fields:
            kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel)
            kwargs['help_text'] = ''
        elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)):
            kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))

        return db_field.formfield(**kwargs)

    def _declared_fieldsets(self):
        if self.fieldsets:
            return self.fieldsets
        elif self.fields:
            return [(None, {'fields': self.fields})]
        return None
    declared_fieldsets = property(_declared_fieldsets)
